#include <kstdio.h>
#include <BuddyAllocator.h>
#include <SlabAllocator.h>
#include <Interrapt.h>
#include <Proc.h>
#include <VFS.h>
#include <Elf.h>
#include <PageTable.h>
#include <Segments.h>

extern "C" void kernel_start(uint32 argc, void **argv);
Frame *mem_map;
BuddyFrameManager *zone_normal;

/*Выделяем первый свободный фрейм под хранение объекта zone_normal*/
void * getFirstFreeFrame(Frame *mm, uint32 sz){
	uint32 i;
	for(i = 0x100000 / 4096; i < sz; i++){
		if(mm[i]._reserved == 0) break;
	}
	return (void *)(((&mm[i] - mm) << PAGE_SHIFT) + 0xC0000000);
}


//Прерывание таймера
unsigned int tmr = 1;
	
void timerInterrapt(){
	//kprintf(".");
	interrapt_in();
	
	if(tmr == 0){
		Proc *prc = current->getOwner();
		if(!prc->getTik()){
			prc->setFlag(NEED_RESCHED_PROC);
		}
		kprintf("*");
	}
	tmr++;
	if(tmr > 100) tmr = 0;
	if(current->getOwner()->getFlag(NEED_RESCHED_PROC)){
		kprintf("\nTIME_INT: CALL RESCHEDULER\n");//KSTOP;
		int_ack();
		pm->schedule();
		kprintf("\nTIME_INT: RET FROM\n");
	}
	interrapt_out();
}

uint32 testSysCall(reg_t *reg){
	//kprintf("ebx: %i\n", reg->ebx);
	if(reg->ecx) kprintf("N:%X\n", reg->ebx);
	else kprintf("%c", reg->ebx);
	return 0;
}
	
PageTable *globalPageDir;
Gdt *gdt;

void kernel_start(uint32 argc, void **argv){
	uint32 frame_map_size;
	init_tty();
	clear();
	mem_map = (Frame *) argv[0];
	frame_map_size = (uint32) argv[1];
	kprintf("FMSIZE: %i\n", frame_map_size);
	//for(;;);
	//Инициализируем менеджер фреймов
	zone_normal = new(getFirstFreeFrame(mem_map, frame_map_size)) BuddyFrameManager(mem_map, frame_map_size);
	//BuddyFrameManager zone_normal(mem_map, frame_map_size);
	kprintf("Zone_normal_addr: %X\n", zone_normal);
	zone_normal->printManager();\
	zone_normal->allocFrame(0);
	
	commonAllocator = new((void *)(zone_normal + 1)) CommonAllocator();
	
	
	//Инициализация распределителя памяти распределителей
	privateAllocator = new((void *)(commonAllocator + 1)) SlabAllocator(sizeof(SlabAllocator));

	//zone_normal->_allocFrame(0);
	kprintf("*BALLOC_MAP*:");
	zone_normal->printManager();
	/*<Инициализация управления таблицами страниц>*/
	
	globalPageDir = new PageTable(2, (page_t *)argv[2]);
	kprintf("GPD: %X\n", globalPageDir);
	page_t *rt = globalPageDir->root;
	//rt[0] = 0;
	int ll;
	for(ll = 0; ll < 1024; ll++){
		if(rt[ll] > 0)
		kprintf("[%i]%X ", ll, rt[ll]);
	}
	kprintf("\n");
	//for(;;);
	
	kprintf("!BALLOC_MAP!:");
	zone_normal->printManager();
	
	globalPageDir->enable_paging((addr_t)_pa(globalPageDir->root));
	kprintf("Hello!\n");
	VIDEO_RAM = (char *)_va(VIDEO_RAM);
	//for(;;);
	/*</Инициализация управления таблицами страниц>*/
	
	
	gdt = (Gdt *) argv[3];
	kprintf("GDT: %X\n", gdt);
	//for(;;);
	/*<Инициализация файловой системы>*/
	kprintf("RAMFS: %X, RAMFS_SIZE: %i\n", argv[4], argv[5]);
	
	kprintf("BALLOC_MAP:");
	zone_normal->printManager();
	
	struct FName *fna = (struct FName *)zone_normal->allocFrame(0);
	fna[0].fname[0] = 'i';
	fna[0].fname[1] = 'n';
	fna[0].fname[2] = 'i';
	fna[0].fname[3] = 't';
	fna[0].fname[4] = '\0';
	fna[0].start = (char *)_va(argv[4]);
	fna[0].size = (size_t)argv[5];
	
	SuperBlock *sb = new SuperBlock(fna, 1);
	addr_t *buf = (addr_t *)zone_normal->allocFrame(0);
	
	vfs = new VFS(sb);
	/*</Инициализация файловой системы>*/
	
	kprintf("BALLOC_MAP:");
	zone_normal->printManager();
	
	
	
	DataSource *ds = vfs->open("init");
	kprintf("DataSource: %X\n", ds);
	//for(;;);
	kprintf("DS Read bytes: %i\n", ds->read((char *)buf, 128));
	int g;
	uint32 *bf = (uint32 *) buf;
	for(g = 0; g < 128 / 4;g++){
		kprintf("%X ", bf[g]);
	}
	
	int z;
	Elf *e_hdr = new Elf(buf);
	kprintf("Init start addr: %X\n", e_hdr->getEntery());
	kprintf("Init PHeaderNr: %i\n", e_hdr->getPHeaderNr());
	for(z = 0; z < e_hdr->getPHeaderNr();z++){
		kprintf("type: %X, vaddr: %X, memsz: %i, filesz: %i\n", e_hdr->getPHeader(z)->p_type, e_hdr->getPHeader(z)->p_vaddr, e_hdr->getPHeader(z)->p_memsz, e_hdr->getPHeader(z)->p_filesz);
	}
	
	
	
	//for(;;);
	//asm("cli");
	
	im = new((void *)(_va(zone_normal->allocFrame(0)))) Interrapt();
	im->loadIDTR();
	im->setNullInts();
	im->setInterrapt(&timerInterrapt, 0x20, SD_486INTGT);
	im->setInterrapt(&pageFoultInterrapt, 14, SD_486INTGT);
	im->setInterrapt(&gp_interrapt, 13, SD_486INTGT);
	im->setInterrapt(&np_interrapt, 11, SD_486INTGT);
	im->setInterrapt(&sys_interrapt, 0x80, 15);
	im->setInterrapt(&nop_interrapt, 6, SD_486INTGT);
	//im->intOn();
	sc = new() SystemCall();
	sc->regSysCall(&testSysCall, 0);
	sc->regSysCall(&forkSysCall, 1);
	//for(;;);
	//Инициализаация менеджера процессов
	procAllocator = new(privateAllocator) SlabAllocator(sizeof(Proc));
	threadAllocator = new(privateAllocator) SlabAllocator(sizeof(Thread));
	//SlabAllocator *pmAlloc = new(privateAllocator) SlabAllocator(sizeof(ProcManager));
	
	pm = new ProcManager();
	//pm->createInit();
	//pm->startInit();
	pm->execInit("init");
	//uint32 *a = (uint32 *) 0xccc00000;
	//*a = 34;
	for(;;);
}


